package com.itheima.article.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.article.dto.ArticleBehaviourDtoQuery;
import com.itheima.article.dto.ArticleHomeDto;
import com.itheima.article.dto.ArticleInfoDto;
import com.itheima.article.mapper.ApArticleConfigMapper;
import com.itheima.article.mapper.ApArticleContentMapper;
import com.itheima.article.mapper.ApArticleMapper;
import com.itheima.article.mapper.ApCollectionMapper;
import com.itheima.article.pojo.ApArticle;
import com.itheima.article.pojo.ApArticleConfig;
import com.itheima.article.pojo.ApArticleContent;
import com.itheima.article.pojo.ApCollection;
import com.itheima.article.service.ApArticleService;
import com.itheima.article.vo.ArticleInfoVo;
import com.itheima.behaviour.feign.ApBehaviorEntryFeign;
import com.itheima.behaviour.feign.ApLikesBehaviorFeign;
import com.itheima.behaviour.feign.ApUnlikesBehaviorFeign;
import com.itheima.behaviour.pojo.ApBehaviorEntry;
import com.itheima.behaviour.pojo.ApLikesBehavior;
import com.itheima.behaviour.pojo.ApUnlikesBehavior;
import com.itheima.common.constants.BusinessConstants;
import com.itheima.common.constants.SystemConstants;
import com.itheima.common.exception.LeadNewsException;
import com.itheima.common.util.RequestContextUtil;
import com.itheima.common.vo.PageResultVo;
import com.itheima.common.vo.ResultVo;
import com.itheima.user.feign.ApUserFollowFeign;
import com.itheima.user.pojo.ApUserFollow;
import com.itheima.wemedia.feign.WmNewsFeign;
import com.itheima.wemedia.pojo.WmNews;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @description <p>已发布的文章信息 业务实现</p>
 *
 * @version 1.0
 * @package com.itheima.article.service.impl
 */
@Service
@Slf4j
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {

    @Autowired
    private ApArticleContentMapper apArticleContentMapper;

    @Autowired
    private ApArticleConfigMapper apArticleConfigMapper;

    @Autowired
    private WmNewsFeign wmNewsFeign;

    @Autowired
    private ApBehaviorEntryFeign apBehaviorEntryFeign;

    @Autowired
    private ApUnlikesBehaviorFeign apUnlikesBehaviorFeign;

    @Autowired
    private ApLikesBehaviorFeign apLikesBehaviorFeign;

    @Autowired
    private ApUserFollowFeign apUserFollowFeign;

    @Autowired
    private ApCollectionMapper apCollectionMapper;
    /**
     * 同步自媒体文章到文章微服
     *
     * @param dto
     */
    @Override
    @Transactional
    public void saveArticleInfo(ArticleInfoDto dto) {
        log.info("文章微服：开始同步文章信息");
        //1.保存文章表数据
        ApArticle apArticle = dto.getApArticle();
        Long articleId = apArticle.getId();
        if (null != articleId) {

            //TODO 这里使用了直接删除，会导致ES索引出现问题，后续改成逻辑删除，
            // 定时任务每天晚上直接删除逻辑删除过后的数据和索引

            // 说明不是第一次同步，要先删除原有数据
            // 删除旧有文章数据
            removeById(articleId);
            // 删除旧有文章内容
            Map<String, Object> querMap = Collections.singletonMap("article_id", articleId);
            apArticleContentMapper.deleteByMap(querMap);
            // 旧有文章配置表
            apArticleConfigMapper.deleteByMap(querMap);

            // 置为空值，此时apArticle的id有数据，要设置为null再执行下方新增，产生新的id
            apArticle.setId(null);
        }
        save(apArticle);
        log.info("保存文章信息成功...");
        // 获取新增的文章id
        articleId = apArticle.getId();
        //2.保存文章内容
        ApArticleContent apArticleContent = dto.getApArticleContent();
        apArticleContent.setArticleId(articleId);
        apArticleContentMapper.insert(apArticleContent);
        log.info("保存文章内容成功...");
        //3.保存文章配置
        ApArticleConfig apArticleConfig = dto.getApArticleConfig();
        apArticleConfig.setArticleId(articleId);
        apArticleConfigMapper.insert(apArticleConfig);
        log.info("保存文章配置成功...");
        //4.更新自媒体文章的状态，文章的article_id
        WmNews wmNews = new WmNews();
        wmNews.setId(dto.getWmNewsId());
        //wmNews中的id要用long类型
        wmNews.setArticleId(articleId);
        // 状态为已发布+上架
        wmNews.setStatus(BusinessConstants.WmNewsConstants.STATUS_PUBLISHED);
        wmNews.setEnable(BusinessConstants.WmNewsConstants.ENABLE_ON);
        ResultVo<WmNews> updateResult = wmNewsFeign.update(wmNews);
        if(!updateResult.isSuccess()){
            //没更新成功，报错让事务回滚
            throw new LeadNewsException("远程调用更新自媒体文章状态失败. 文章数据同步");
        }
        log.info("远程调用更新自媒体文章状态成功...");
    }

    /**
     * 分页查询
     * @param dto
     * @return
     */
    @Override
    public PageResultVo<ApArticle> findPage(ArticleHomeDto dto, int loadType) {
        //参数检查
        dto.checkSize();
        //时间参数处理
        if(dto.getMaxBehotTime() == null) dto.setMaxBehotTime(new Date());
        if(dto.getMinBehotTime() == null) dto.setMinBehotTime(new Date());
        // 设置分页参数
        IPage<ApArticle> page = new Page<ApArticle>(dto.getLoaddir(),dto.getSize());
        // 查询
        List<ApArticle> list = getBaseMapper().findPage(page, dto, loadType);
        // 返回结果
        return PageResultVo.pageResult(dto.getLoaddir(),dto.getSize(), page.getTotal(), list);
    }

    /**
     * 加载文章详情
     *
     * @param paramMap
     * @return
     */
    @Override
    public ArticleInfoVo loadArticleInfo(Map<String, String> paramMap) {
        //1. 获取文章ID
        Long articleId = Long.parseLong(paramMap.get("articleId"));
        //2. 查询文章配置信息
        LambdaQueryWrapper<ApArticleConfig> queryWrapper = Wrappers.<ApArticleConfig>lambdaQuery()
                .eq(ApArticleConfig::getArticleId,articleId)
                .eq(ApArticleConfig::getIsDelete, 0)
                .eq(ApArticleConfig::getIsDown, 0);
        ApArticleConfig articleConfig = apArticleConfigMapper.selectOne(queryWrapper);
        if(null == articleConfig){
            throw new LeadNewsException("文章已下架或已删除!");
        }
        //3. 查询文章内容
        LambdaQueryWrapper<ApArticleContent> contentQueryWrapper = Wrappers.<ApArticleContent>lambdaQuery()
                .eq(ApArticleContent::getArticleId, articleId);
        ApArticleContent articleContent = apArticleContentMapper.selectOne(contentQueryWrapper);
        //4. 组装vo
        ArticleInfoVo vo = new ArticleInfoVo();
        vo.setConfig(articleConfig);
        vo.setContent(articleContent);
        //5. 返回
        return vo;
    }

    /**
     * 加载用户对文章的行为
     *
     * @param dto
     * @return
     */
    @Override
    public Map<String, Boolean> loadArticleBehaviour(ArticleBehaviourDtoQuery dto) {
        /**
         * {
         *   "islike": false, //是否点赞
         *   "isunlike": false, //是否不喜欢
         *   "iscollection": false, // 是否收藏
         *   "isfollow": false //是否关注了作者
         * }
         */
        // 默认都为false
        boolean islike = false;
        boolean isunlike = false;
        boolean iscollection = false;
        boolean isfollow = false;
        //1. 查询行为实体 ===》 行为微服务
        ApBehaviorEntry entry = queryEntry(dto.getEquipmentId());
        if(null != entry){
            //2. 查询是否不喜欢 ===》 行为微服务
            isunlike = queryIsUnlike(dto.getArticleId(),entry.getId());
            //3. 查询是否关注 ===》 用户微服务
            isfollow = queryIsFollow(RequestContextUtil.getLoginUserId(), dto.getAuthorId());
            //4. 查询是否点赞 ===》 行为微服务
            islike = queryIsLike(dto.getArticleId(),entry.getId());
            //5. 查询是否收藏 ===》 文章微服务
            iscollection = queryIsCollection(dto,entry.getId());
        }

        Map<String, Boolean> resultMap = new HashMap<String,Boolean>();
        resultMap.put("islike",islike);
        resultMap.put("isunlike",isunlike);
        resultMap.put("iscollection",iscollection);
        resultMap.put("isfollow",isfollow);
        return resultMap;
    }

    /**
     * 查询是否点赞喜欢文章
     * @param articleId
     * @param id
     * @return
     */
    private boolean queryIsLike(Long articleId, Integer id) {
        ResultVo<ApLikesBehavior> result = apLikesBehaviorFeign.findByUserIdOrEquipmentId(articleId, id);
        if(!result.isSuccess()){
            throw new LeadNewsException("查询用户行为失败!");
        }
        ApLikesBehavior data = result.getData();
        if(null != data && data.getOperation() == 1){ //1为点赞
            return true;
        }
        return false;
    }

    /**
     * 查询当前用户是否关注了作者
     * @param loginUserId
     * @param authorId
     * @return
     */
    private boolean queryIsFollow(String loginUserId, Integer authorId) {
        int userId = Integer.parseInt(loginUserId);
        ResultVo<ApUserFollow> result = apUserFollowFeign.findUserFollow(Integer.parseInt(loginUserId),authorId);
        if(!result.isSuccess()){
            throw new LeadNewsException("查询用户行为失败!");
        }
        ApUserFollow data = result.getData();
        if(null != data){
            // 有数据即为关注，因此取消关注时，会删除数据
            return true;
        }
        return false;
    }

    /**
     * 查询用户是否 不喜欢文章
     * @param articleId
     * @param entryId
     * @return
     */
    private boolean queryIsUnlike(Long articleId, Integer entryId){
        long aId = articleId.longValue();
        int eid = entryId.intValue();
        ResultVo<ApUnlikesBehavior> result = apUnlikesBehaviorFeign.findByUserIdOrEquipmentId(aId, eid);
        if(!result.isSuccess()){
            throw new LeadNewsException("查询用户行为失败!");
        }
        ApUnlikesBehavior data = result.getData();
        // type=0: 不喜欢，1=取消不喜欢
        if(null == data || data.getType() != 0){
            //没找到数据，即用户没有做过这种行为，则默认为 没有不喜欢
            return false;
        }
        //type=0
        return true;
    }

    /**
     * 查询是否收藏
     * @param dto
     * @param id
     * @return
     */
    private boolean queryIsCollection(ArticleBehaviourDtoQuery dto, Integer id) {
        LambdaQueryWrapper<ApCollection> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ApCollection::getArticleId,dto.getArticleId())
                .eq(ApCollection::getEntryId,id)
                .eq(ApCollection::getType,0);
        return apCollectionMapper.selectCount(lqw)>0;
    }

    /**
     * 查询行为实体
     * @param eqId
     * @return
     */
    private ApBehaviorEntry queryEntry(Integer eqId){
        // 判断操作实体是匿名还是登录用户
        int loginUserId = Integer.parseInt(RequestContextUtil.getLoginUserId());
        // 假设实体为当前登录用户id
        int entryId = loginUserId;
        // 假设实体类型为用户
        int type = SystemConstants.TYPE_USER;
        if(SystemConstants.ANONYMOUS_USER_ID == loginUserId){
            //如果是匿名，则实体类型为备
            type = SystemConstants.TYPE_E;
            //那么相应的，实体Id就为设备的id
            entryId = eqId;
        }
        ResultVo<ApBehaviorEntry> entryResult = apBehaviorEntryFeign.findByUserIdOrEquipmentId(entryId, type);
        if (!entryResult.isSuccess()) {
            throw new LeadNewsException("查询用户行为失败!");
        }
        return entryResult.getData();
    }
}
